home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 26 / AACD 26.iso / AACD / Online / x3270 / unix_files / trace_ds.c < prev    next >
Encoding:
C/C++ Source or Header  |  2009-02-27  |  20.4 KB  |  988 lines

  1. /*
  2.  * Copyright 1993, 1994, 1995, 1999, 2000 by Paul Mattes.
  3.  *  Permission to use, copy, modify, and distribute this software and its
  4.  *  documentation for any purpose and without fee is hereby granted,
  5.  *  provided that the above copyright notice appear in all copies and that
  6.  *  both that copyright notice and this permission notice appear in
  7.  *  supporting documentation.
  8.  */
  9.  
  10. /*
  11.  *    trace_ds.c
  12.  *        3270 data stream tracing.
  13.  *
  14.  */
  15.  
  16. #include "globals.h"
  17.  
  18. #if defined(X3270_TRACE) /*[*/
  19.  
  20. #if defined(X3270_DISPLAY) /*[*/
  21. #include <X11/StringDefs.h>
  22. #include <X11/Xaw/Dialog.h>
  23. #endif /*]*/
  24. #include <errno.h>
  25. #include <signal.h>
  26. #include <time.h>
  27. #include <stdarg.h>
  28. #include <fcntl.h>
  29. #include "3270ds.h"
  30. #include "appres.h"
  31. #include "objects.h"
  32. #include "resources.h"
  33. #include "ctlr.h"
  34.  
  35. #include "ctlrc.h"
  36. #include "menubarc.h"
  37. #include "popupsc.h"
  38. #include "printc.h"
  39. #include "savec.h"
  40. #include "tablesc.h"
  41. #include "telnetc.h"
  42. #include "trace_dsc.h"
  43. #include "utilc.h"
  44.  
  45. /* Statics */
  46. static int      dscnt = 0;
  47. static int      tracewindow_pid = -1;
  48.  
  49. /* Globals */
  50. FILE           *tracef = (FILE *) 0;
  51. struct timeval  ds_ts;
  52. Boolean         trace_skipping = False;
  53.  
  54. static const char *
  55. unknown(unsigned char value)
  56. {
  57.     static char buf[64];
  58.  
  59.     (void) sprintf(buf, "unknown[0x%x]", value);
  60.     return buf;
  61. }
  62.  
  63. /* display a (row,col) */
  64. const char *
  65. rcba(int baddr)
  66. {
  67.     static char buf[16];
  68.  
  69.     (void) sprintf(buf, "(%d,%d)", baddr/COLS + 1, baddr%COLS + 1);
  70.     return buf;
  71. }
  72.  
  73. const char *
  74. see_ebc(unsigned char ch)
  75. {
  76.     static char buf[8];
  77.  
  78.     switch (ch) {
  79.         case FCORDER_NULL:
  80.         return "NULL";
  81.         case FCORDER_SUB:
  82.         return "SUB";
  83.         case FCORDER_DUP:
  84.         return "DUP";
  85.         case FCORDER_FM:
  86.         return "FM";
  87.         case FCORDER_FF:
  88.         return "FF";
  89.         case FCORDER_CR:
  90.         return "CR";
  91.         case FCORDER_NL:
  92.         return "NL";
  93.         case FCORDER_EM:
  94.         return "EM";
  95.         case FCORDER_EO:
  96.         return "EO";
  97.     }
  98.     if (ebc2asc[ch])
  99.         (void) sprintf(buf, "%c", ebc2asc[ch]);
  100.     else
  101.         (void) sprintf(buf, "\\%o", ch);
  102.     return buf;
  103. }
  104.  
  105. const char *
  106. see_aid(unsigned char code)
  107. {
  108.     switch (code) {
  109.     case AID_NO: 
  110.         return "NoAID";
  111.     case AID_ENTER: 
  112.         return "Enter";
  113.     case AID_PF1: 
  114.         return "PF1";
  115.     case AID_PF2: 
  116.         return "PF2";
  117.     case AID_PF3: 
  118.         return "PF3";
  119.     case AID_PF4: 
  120.         return "PF4";
  121.     case AID_PF5: 
  122.         return "PF5";
  123.     case AID_PF6: 
  124.         return "PF6";
  125.     case AID_PF7: 
  126.         return "PF7";
  127.     case AID_PF8: 
  128.         return "PF8";
  129.     case AID_PF9: 
  130.         return "PF9";
  131.     case AID_PF10: 
  132.         return "PF10";
  133.     case AID_PF11: 
  134.         return "PF11";
  135.     case AID_PF12: 
  136.         return "PF12";
  137.     case AID_PF13: 
  138.         return "PF13";
  139.     case AID_PF14: 
  140.         return "PF14";
  141.     case AID_PF15: 
  142.         return "PF15";
  143.     case AID_PF16: 
  144.         return "PF16";
  145.     case AID_PF17: 
  146.         return "PF17";
  147.     case AID_PF18: 
  148.         return "PF18";
  149.     case AID_PF19: 
  150.         return "PF19";
  151.     case AID_PF20: 
  152.         return "PF20";
  153.     case AID_PF21: 
  154.         return "PF21";
  155.     case AID_PF22: 
  156.         return "PF22";
  157.     case AID_PF23: 
  158.         return "PF23";
  159.     case AID_PF24: 
  160.         return "PF24";
  161.     case AID_OICR: 
  162.         return "OICR";
  163.     case AID_MSR_MHS: 
  164.         return "MSR_MHS";
  165.     case AID_SELECT: 
  166.         return "Select";
  167.     case AID_PA1: 
  168.         return "PA1";
  169.     case AID_PA2: 
  170.         return "PA2";
  171.     case AID_PA3: 
  172.         return "PA3";
  173.     case AID_CLEAR: 
  174.         return "Clear";
  175.     case AID_SYSREQ: 
  176.         return "SysReq";
  177.     case AID_QREPLY:
  178.         return "QueryReplyAID";
  179.     default: 
  180.         return unknown(code);
  181.     }
  182. }
  183.  
  184. const char *
  185. see_attr(unsigned char fa)
  186. {
  187.     static char buf[256];
  188.     const char *paren = "(";
  189.  
  190.     buf[0] = '\0';
  191.  
  192.     if (fa & 0x04) {
  193.         (void) strcat(buf, paren);
  194.         (void) strcat(buf, "protected");
  195.         paren = ",";
  196.         if (fa & 0x08) {
  197.             (void) strcat(buf, paren);
  198.             (void) strcat(buf, "skip");
  199.             paren = ",";
  200.         }
  201.     } else if (fa & 0x08) {
  202.         (void) strcat(buf, paren);
  203.         (void) strcat(buf, "numeric");
  204.         paren = ",";
  205.     }
  206.     switch (fa & 0x03) {
  207.     case 0:
  208.         break;
  209.     case 1:
  210.         (void) strcat(buf, paren);
  211.         (void) strcat(buf, "detectable");
  212.         paren = ",";
  213.         break;
  214.     case 2:
  215.         (void) strcat(buf, paren);
  216.         (void) strcat(buf, "intensified");
  217.         paren = ",";
  218.         break;
  219.     case 3:
  220.         (void) strcat(buf, paren);
  221.         (void) strcat(buf, "nondisplay");
  222.         paren = ",";
  223.         break;
  224.     }
  225.     if (fa & 0x20) {
  226.         (void) strcat(buf, paren);
  227.         (void) strcat(buf, "modified");
  228.         paren = ",";
  229.     }
  230.     if (strcmp(paren, "("))
  231.         (void) strcat(buf, ")");
  232.     else
  233.         (void) strcpy(buf, "(default)");
  234.  
  235.     return buf;
  236. }
  237.  
  238. static const char *
  239. see_highlight(unsigned char setting)
  240. {
  241.     switch (setting) {
  242.         case XAH_DEFAULT:
  243.         return "default";
  244.         case XAH_NORMAL:
  245.         return "normal";
  246.         case XAH_BLINK:
  247.         return "blink";
  248.         case XAH_REVERSE:
  249.         return "reverse";
  250.         case XAH_UNDERSCORE:
  251.         return "underscore";
  252.         case XAH_INTENSIFY:
  253.         return "intensify";
  254.         default:
  255.         return unknown(setting);
  256.     }
  257. }
  258.  
  259. #if !defined(X3270_DISPLAY) /*[*/
  260. static
  261. #endif /*]*/
  262. const char *
  263. see_color(unsigned char setting)
  264. {
  265.     static const char *color_name[] = {
  266.         "neutralBlack",
  267.         "blue",
  268.         "red",
  269.         "pink",
  270.         "green",
  271.         "turquoise",
  272.         "yellow",
  273.         "neutralWhite",
  274.         "black",
  275.         "deepBlue",
  276.         "orange",
  277.         "purple",
  278.         "paleGreen",
  279.         "paleTurquoise",
  280.         "grey",
  281.         "white"
  282.     };
  283.  
  284.     if (setting == XAC_DEFAULT)
  285.         return "default";
  286.     else if (setting < 0xf0 || setting > 0xff)
  287.         return unknown(setting);
  288.     else
  289.         return color_name[setting - 0xf0];
  290. }
  291.  
  292. static const char *
  293. see_transparency(unsigned char setting)
  294. {
  295.     switch (setting) {
  296.         case XAT_DEFAULT:
  297.         return "default";
  298.         case XAT_OR:
  299.         return "or";
  300.         case XAT_XOR:
  301.         return "xor";
  302.         case XAT_OPAQUE:
  303.         return "opaque";
  304.         default:
  305.         return unknown(setting);
  306.     }
  307. }
  308.  
  309. static const char *
  310. see_validation(unsigned char setting)
  311. {
  312.     static char buf[64];
  313.     const char *paren = "(";
  314.  
  315.     (void) strcpy(buf, "");
  316.     if (setting & XAV_FILL) {
  317.         (void) strcat(buf, paren);
  318.         (void) strcat(buf, "fill");
  319.         paren = ",";
  320.     }
  321.     if (setting & XAV_ENTRY) {
  322.         (void) strcat(buf, paren);
  323.         (void) strcat(buf, "entry");
  324.         paren = ",";
  325.     }
  326.     if (setting & XAV_TRIGGER) {
  327.         (void) strcat(buf, paren);
  328.         (void) strcat(buf, "trigger");
  329.         paren = ",";
  330.     }
  331.     if (strcmp(paren, "("))
  332.         (void) strcat(buf, ")");
  333.     else
  334.         (void) strcpy(buf, "(none)");
  335.     return buf;
  336. }
  337.  
  338. static const char *
  339. see_outline(unsigned char setting)
  340. {
  341.     static char buf[64];
  342.     const char *paren = "(";
  343.  
  344.     (void) strcpy(buf, "");
  345.     if (setting & XAO_UNDERLINE) {
  346.         (void) strcat(buf, paren);
  347.         (void) strcat(buf, "underline");
  348.         paren = ",";
  349.     }
  350.     if (setting & XAO_RIGHT) {
  351.         (void) strcat(buf, paren);
  352.         (void) strcat(buf, "right");
  353.         paren = ",";
  354.     }
  355.     if (setting & XAO_OVERLINE) {
  356.         (void) strcat(buf, paren);
  357.         (void) strcat(buf, "overline");
  358.         paren = ",";
  359.     }
  360.     if (setting & XAO_LEFT) {
  361.         (void) strcat(buf, paren);
  362.         (void) strcat(buf, "left");
  363.         paren = ",";
  364.     }
  365.     if (strcmp(paren, "("))
  366.         (void) strcat(buf, ")");
  367.     else
  368.         (void) strcpy(buf, "(none)");
  369.     return buf;
  370. }
  371.  
  372. const char *
  373. see_efa(unsigned char efa, unsigned char value)
  374. {
  375.     static char buf[64];
  376.  
  377.     switch (efa) {
  378.         case XA_ALL:
  379.         (void) sprintf(buf, " all(%x)", value);
  380.         break;
  381.         case XA_3270:
  382.         (void) sprintf(buf, " 3270%s", see_attr(value));
  383.         break;
  384.         case XA_VALIDATION:
  385.         (void) sprintf(buf, " validation%s", see_validation(value));
  386.         break;
  387.         case XA_OUTLINING:
  388.         (void) sprintf(buf, " outlining(%s)", see_outline(value));
  389.         break;
  390.         case XA_HIGHLIGHTING:
  391.         (void) sprintf(buf, " highlighting(%s)", see_highlight(value));
  392.         break;
  393.         case XA_FOREGROUND:
  394.         (void) sprintf(buf, " foreground(%s)", see_color(value));
  395.         break;
  396.         case XA_CHARSET:
  397.         (void) sprintf(buf, " charset(%x)", value);
  398.         break;
  399.         case XA_BACKGROUND:
  400.         (void) sprintf(buf, " background(%s)", see_color(value));
  401.         break;
  402.         case XA_TRANSPARENCY:
  403.         (void) sprintf(buf, " transparency(%s)", see_transparency(value));
  404.         break;
  405.         default:
  406.         (void) sprintf(buf, " %s[0x%x]", unknown(efa), value);
  407.     }
  408.     return buf;
  409. }
  410.  
  411. const char *
  412. see_efa_only(unsigned char efa)
  413. {
  414.     switch (efa) {
  415.         case XA_ALL:
  416.         return "all";
  417.         case XA_3270:
  418.         return "3270";
  419.         case XA_VALIDATION:
  420.         return "validation";
  421.         case XA_OUTLINING:
  422.         return "outlining";
  423.         case XA_HIGHLIGHTING:
  424.         return "highlighting";
  425.         case XA_FOREGROUND:
  426.         return "foreground";
  427.         case XA_CHARSET:
  428.         return "charset";
  429.         case XA_BACKGROUND:
  430.         return "background";
  431.         case XA_TRANSPARENCY:
  432.         return "transparency";
  433.         default:
  434.         return unknown(efa);
  435.     }
  436. }
  437.  
  438. const char *
  439. see_qcode(unsigned char id)
  440. {
  441.     static char buf[64];
  442.  
  443.     switch (id) {
  444.         case QR_CHARSETS:
  445.         return "CharacterSets";
  446.         case QR_IMP_PART:
  447.         return "ImplicitPartition";
  448.         case QR_SUMMARY:
  449.         return "Summary";
  450.         case QR_USABLE_AREA:
  451.         return "UsableArea";
  452.         case QR_COLOR:
  453.         return "Color";
  454.         case QR_HIGHLIGHTING:
  455.         return "Highlighting";
  456.         case QR_REPLY_MODES:
  457.         return "ReplyModes";
  458.         case QR_ALPHA_PART:
  459.         return "AlphanumericPartitions";
  460.         case QR_DDM:
  461.         return "DistributedDataManagement";
  462.         default:
  463.         (void) sprintf(buf, "unknown[0x%x]", id);
  464.         return buf;
  465.     }
  466. }
  467.  
  468. /* Data Stream trace print, handles line wraps */
  469.  
  470. static char *tdsbuf = CN;
  471. #define TDS_LEN    75
  472.  
  473. static void
  474. trace_ds_s(char *s)
  475. {
  476.     int len = strlen(s);
  477.     Boolean nl = False;
  478.  
  479.     if (!toggled(DS_TRACE) || !len)
  480.         return;
  481.  
  482.     if (s && s[len-1] == '\n') {
  483.         len--;
  484.         nl = True;
  485.     }
  486.     while (dscnt + len >= 75) {
  487.         int plen = 75-dscnt;
  488.  
  489.         (void) fprintf(tracef, "%.*s ...\n... ", plen, s);
  490.         dscnt = 4;
  491.         s += plen;
  492.         len -= plen;
  493.     }
  494.     if (len) {
  495.         (void) fprintf(tracef, "%.*s", len, s);
  496.         dscnt += len;
  497.     }
  498.     if (nl) {
  499.         (void) fprintf(tracef, "\n");
  500.         dscnt = 0;
  501.     }
  502. }
  503.  
  504. void
  505. trace_ds(const char *fmt, ...)
  506. {
  507.     va_list args;
  508.  
  509.     va_start(args, fmt);
  510.  
  511.     /* allocate buffer */
  512.     if (tdsbuf == CN)
  513.         tdsbuf = Malloc(4096);
  514.  
  515.     /* print out remainder of message */
  516.     (void) vsprintf(tdsbuf, fmt, args);
  517.     trace_ds_s(tdsbuf);
  518.     va_end(args);
  519. }
  520.  
  521. /* Conditional event trace. */
  522. void
  523. trace_event(const char *fmt, ...)
  524. {
  525.     va_list args;
  526.  
  527.     if (!toggled(EVENT_TRACE) || tracef == (FILE *)NULL)
  528.         return;
  529.  
  530.     va_start(args, fmt);
  531.  
  532.     /* print out message */
  533.     (void) vfprintf(tracef, fmt, args);
  534.     va_end(args);
  535. }
  536.  
  537. #if defined(X3270_DISPLAY) /*[*/
  538. static Widget trace_shell = (Widget)NULL;
  539. #endif
  540. static int trace_reason;
  541.  
  542. /* Callback for "OK" button on trace popup */
  543. static void
  544. tracefile_callback(Widget w, XtPointer client_data, XtPointer call_data unused)
  545. {
  546.     char *tfn;
  547.     char *tracecmd;
  548.     char *full_cmd;
  549.     time_t clk;
  550.     Boolean piped = False;
  551.     int pipefd[2];
  552.  
  553. #if defined(X3270_DISPLAY) /*[*/
  554.     if (w)
  555.         tfn = XawDialogGetValueString((Widget)client_data);
  556.     else
  557. #endif /*]*/
  558.         tfn = (char *)client_data;
  559.     tfn = do_subst(tfn, True, True);
  560.     if (strchr(tfn, '\'') ||
  561.         ((int)strlen(tfn) > 0 && tfn[strlen(tfn)-1] == '\\')) {
  562.         popup_an_error("Illegal file name: %s\n", tfn);
  563.         Free(tfn);
  564.         return;
  565.     }
  566.     if (!strcmp(tfn, "stdout")) {
  567.         tracef = stdout;
  568.     } else if (!strcmp(tfn, "none") || !tfn[0]) {
  569.  
  570.         if (pipe(pipefd) < 0) {
  571.             popup_an_errno(errno, "pipe() failed");
  572.             Free(tfn);
  573.             return;
  574.         }
  575.         tracef = fdopen(pipefd[1], "w");
  576.         if (tracef == (FILE *)NULL) {
  577.             popup_an_errno(errno, "fdopen() failed");
  578.             Free(tfn);
  579.             return;
  580.         }
  581.         (void) SETLINEBUF(tracef);
  582.         (void) fcntl(pipefd[1], F_SETFD, 1);
  583.         piped = True;
  584.     } else {
  585.         tracef = fopen(tfn, "a");
  586.         if (tracef == (FILE *)NULL) {
  587.             popup_an_errno(errno, tfn);
  588.             Free(tfn);
  589.             return;
  590.         }
  591.         (void) SETLINEBUF(tracef);
  592.         (void) fcntl(fileno(tracef), F_SETFD, 1);
  593.     }
  594.  
  595.     /* Start the monitor window */
  596.     tracecmd = get_resource(ResTraceCommand);
  597.     if (tracecmd == CN || !strcmp(tracecmd, "none") || tracef == stdout)
  598.         goto done;
  599.     switch (tracewindow_pid = fork()) {
  600.         case 0:    /* child process */
  601.         if (piped) {
  602.             char cmd[64];
  603.  
  604.             (void) sprintf(cmd, "cat /dev/fd/%d", pipefd[0]);
  605.             (void) execlp("xterm", "xterm", "-title", "trace",
  606.                 "-sb", "-e", "/bin/sh", "-c", cmd, CN);
  607.         } else {
  608.             full_cmd = xs_buffer("%s <'%s'", tracecmd, tfn);
  609.             (void) execlp("xterm", "xterm", "-title", tfn,
  610.                 "-sb", "-e", "/bin/sh", "-c", full_cmd, CN);
  611.         }
  612.         (void) perror("exec(xterm)");
  613.         _exit(1);
  614.         default:    /* parent */
  615.         if (piped)
  616.             (void) close(pipefd[0]);
  617.         ++children;
  618.         break;
  619.         case -1:    /* error */
  620.         popup_an_errno(errno, "fork()");
  621.         break;
  622.     }
  623.  
  624.     done:
  625.     Free(tfn);
  626.  
  627.     /* Display current status */
  628.     clk = time((time_t *)0);
  629.     (void) fprintf(tracef, "Trace started %s", ctime(&clk));
  630.     (void) fprintf(tracef, " Version: %s\n", build);
  631.     save_yourself();
  632.     (void) fprintf(tracef, " Command: %s\n", command_string);
  633.     (void) fprintf(tracef, " Model %s", model_name);
  634.     (void) fprintf(tracef, ", %s display", 
  635.         appres.mono ? "monochrome" : "color");
  636.     if (appres.extended)
  637.         (void) fprintf(tracef, ", extended data stream");
  638.     if (!appres.mono)
  639.         (void) fprintf(tracef, ", %scolor",
  640.             appres.m3279 ? "full " : "pseudo-");
  641.     if (appres.charset)
  642.         (void) fprintf(tracef, ", %s charset", appres.charset);
  643.     if (appres.apl_mode)
  644.         (void) fprintf(tracef, ", APL mode");
  645.     (void) fprintf(tracef, "\n");
  646.     if (CONNECTED)
  647.         (void) fprintf(tracef, " Connected to %s, port %u\n",
  648.             current_host, current_port);
  649.  
  650.  
  651.     /* We're really tracing, turn the flag on. */
  652.     appres.toggle[trace_reason].value = True;
  653.     appres.toggle[trace_reason].changed = True;
  654.     menubar_retoggle(&appres.toggle[trace_reason]);
  655.  
  656. #if defined(X3270_DISPLAY) /*[*/
  657.     if (w)
  658.         XtPopdown(trace_shell);
  659. #endif /*]*/
  660.  
  661.     /* Snap the current TELNET options. */
  662.     if (net_snap_options()) {
  663.         (void) fprintf(tracef, " TELNET state:\n");
  664.         trace_netdata('<', obuf, obptr - obuf);
  665.     }
  666.  
  667.     /* Dump the screen contents and modes into the trace file. */
  668.     if (CONNECTED) {
  669.         /*
  670.          * Note that if the screen is not formatted, we do not
  671.          * attempt to save what's on it.  However, if we're in
  672.          * 3270 SSCP-LU or NVT mode, we'll do a dummy, empty
  673.          * write to ensure that the display is in the right
  674.          * mode.
  675.          */
  676.         if (formatted) {
  677.             (void) fprintf(tracef, " Screen contents:\n");
  678.             obptr = obuf;
  679. #if defined(X3270_TN3270E) /*[*/
  680.             (void) net_add_dummy_tn3270e();
  681. #endif /*]*/
  682.             ctlr_snap_buffer();
  683.             space3270out(2);
  684.             net_add_eor(obuf, obptr - obuf);
  685.             obptr += 2;
  686.             trace_netdata('<', obuf, obptr - obuf);
  687.  
  688.             obptr = obuf;
  689. #if defined(X3270_TN3270E) /*[*/
  690.             (void) net_add_dummy_tn3270e();
  691. #endif /*]*/
  692.             if (ctlr_snap_modes()) {
  693.                 (void) fprintf(tracef, " 3270 modes:\n");
  694.                 space3270out(2);
  695.                 net_add_eor(obuf, obptr - obuf);
  696.                 obptr += 2;
  697.                 trace_netdata('<', obuf, obptr - obuf);
  698.             }
  699.         }
  700. #if defined(X3270_TN3270E) /*[*/
  701.         else if (IN_E) {
  702.             obptr = obuf;
  703.             if (net_add_dummy_tn3270e()) {
  704.                 (void) fprintf(tracef,
  705.                     " Screen contents:\n");
  706.                 space3270out(2);
  707.                 net_add_eor(obuf, obptr - obuf);
  708.                 obptr += 2;
  709.                 trace_netdata('<', obuf, obptr - obuf);
  710.             }
  711.         }
  712. #endif /*]*/
  713.     }
  714.  
  715.     (void) fprintf(tracef, " Data stream:\n");
  716. }
  717.  
  718. #if defined(X3270_DISPLAY) /*[*/
  719. /* Callback for "No File" button on trace popup */
  720. static void
  721. no_tracefile_callback(Widget w, XtPointer client_data,
  722.     XtPointer call_data unused)
  723. {
  724.     tracefile_callback((Widget)NULL, "", PN);
  725.     XtPopdown(trace_shell);
  726. }
  727. #endif /*]*/
  728.  
  729. /* Open the trace file. */
  730. static void
  731. tracefile_on(int reason, enum toggle_type tt)
  732. {
  733.     char tracefile_buf[256];
  734.     char *tracefile;
  735.  
  736.     if (tracef)
  737.         return;
  738.  
  739.     trace_reason = reason;
  740.     if (appres.secure) {
  741.         tracefile_callback((Widget)NULL, "none", PN);
  742.         return;
  743.     }
  744.     if (appres.trace_file)
  745.         tracefile = appres.trace_file;
  746.     else {
  747.         (void) sprintf(tracefile_buf, "%s/x3trc.%d", appres.trace_dir,
  748.             getpid());
  749.         tracefile = tracefile_buf;
  750.     }
  751.  
  752. #if defined(X3270_DISPLAY) /*[*/
  753.     if (tt == TT_INITIAL)
  754. #endif /*]*/
  755.     {
  756.         tracefile_callback((Widget)NULL, tracefile, PN);
  757.         return;
  758.     }
  759. #if defined(X3270_DISPLAY) /*[*/
  760.     if (trace_shell == NULL) {
  761.         trace_shell = create_form_popup("trace",
  762.             tracefile_callback, no_tracefile_callback, FORM_NO_WHITE);
  763.         XtVaSetValues(XtNameToWidget(trace_shell, ObjDialog),
  764.             XtNvalue, tracefile,
  765.             NULL);
  766.     }
  767.  
  768.     /* Turn the toggle _off_ until the popup succeeds. */
  769.     appres.toggle[reason].value = False;
  770.     appres.toggle[reason].changed = True;
  771.  
  772.     popup_popup(trace_shell, XtGrabExclusive);
  773. #endif /*]*/
  774. }
  775.  
  776. /* Close the trace file. */
  777. static void
  778. tracefile_off(void)
  779. {
  780.     time_t clk;
  781.  
  782.     clk = time((time_t *)0);
  783.     (void) fprintf(tracef, "Trace stopped %s", ctime(&clk));
  784.     if (tracewindow_pid != -1)
  785.         (void) kill(tracewindow_pid, SIGKILL);
  786.     tracewindow_pid = -1;
  787.     if (tracef != stdout)
  788.         (void) fclose(tracef);
  789.     tracef = (FILE *) NULL;
  790. }
  791.  
  792. void
  793. toggle_dsTrace(struct toggle *t unused, enum toggle_type tt)
  794. {
  795.     /* If turning on trace and no trace file, open one. */
  796.     if (toggled(DS_TRACE) && !tracef)
  797.         tracefile_on(DS_TRACE, tt);
  798.  
  799.     /* If turning off trace and not still tracing events, close the
  800.        trace file. */
  801.     else if (!toggled(DS_TRACE) && !toggled(EVENT_TRACE))
  802.         tracefile_off();
  803.  
  804.     if (toggled(DS_TRACE))
  805.         (void) gettimeofday(&ds_ts, (struct timezone *)NULL);
  806. }
  807.  
  808. void
  809. toggle_eventTrace(struct toggle *t unused, enum toggle_type tt)
  810. {
  811.     /* If turning on event debug, and no trace file, open one. */
  812.     if (toggled(EVENT_TRACE) && !tracef)
  813.         tracefile_on(EVENT_TRACE, tt);
  814.  
  815.     /* If turning off event debug, and not tracing the data stream,
  816.        close the trace file. */
  817.     else if (!toggled(EVENT_TRACE) && !toggled(DS_TRACE))
  818.         tracefile_off();
  819. }
  820.  
  821. /* Screen trace file support. */
  822.  
  823. #if defined(X3270_DISPLAY) /*[*/
  824. static Widget screentrace_shell = (Widget)NULL;
  825. #endif /*]*/
  826. static FILE *screentracef = (FILE *)0;
  827.  
  828. /*
  829.  * Screen trace function, called when the host clears the screen.
  830.  */
  831. static void
  832. do_screentrace(void)
  833. {
  834.     register int i;
  835.  
  836.     if (fprint_screen(screentracef, False)) {
  837.         for (i = 0; i < COLS; i++)
  838.             (void) fputc('=', screentracef);
  839.         (void) fputc('\n', screentracef);
  840.     }
  841. }
  842.  
  843. void
  844. trace_screen(void)
  845. {
  846.     trace_skipping = False;
  847.  
  848.     if (!toggled(SCREEN_TRACE) || !screentracef)
  849.         return;
  850.     do_screentrace();
  851. }
  852.  
  853. /* Called from ANSI emulation code to log a single character. */
  854. void
  855. trace_char(char c)
  856. {
  857.     if (!toggled(SCREEN_TRACE) || !screentracef)
  858.         return;
  859.     (void) fputc(c, screentracef);
  860. }
  861.  
  862. /*
  863.  * Called when disconnecting in ANSI mode, to finish off the trace file
  864.  * and keep the next screen clear from re-recording the screen image.
  865.  * (In a gross violation of data hiding and modularity, trace_skipping is
  866.  * manipulated directly in ctlr_clear()).
  867.  */
  868. void
  869. trace_ansi_disc(void)
  870. {
  871.     int i;
  872.  
  873.     (void) fputc('\n', screentracef);
  874.     for (i = 0; i < COLS; i++)
  875.         (void) fputc('=', screentracef);
  876.     (void) fputc('\n', screentracef);
  877.  
  878.     trace_skipping = True;
  879. }
  880.  
  881. /*
  882.  * Screen tracing callback.
  883.  * Returns True for success, False for failure.
  884.  */
  885. static Boolean
  886. screentrace_cb(char *tfn)
  887. {
  888.     tfn = do_subst(tfn, True, True);
  889.     screentracef = fopen(tfn, "a");
  890.     if (screentracef == (FILE *)NULL) {
  891.         popup_an_errno(errno, tfn);
  892.         Free(tfn);
  893.         return False;
  894.     }
  895.     Free(tfn);
  896.     (void) SETLINEBUF(screentracef);
  897.     (void) fcntl(fileno(screentracef), F_SETFD, 1);
  898.  
  899.     /* We're really tracing, turn the flag on. */
  900.     appres.toggle[SCREEN_TRACE].value = True;
  901.     appres.toggle[SCREEN_TRACE].changed = True;
  902.     menubar_retoggle(&appres.toggle[SCREEN_TRACE]);
  903.     return True;
  904. }
  905.  
  906. #if defined(X3270_DISPLAY) /*[*/
  907. /* Callback for "OK" button on screentrace popup */
  908. static void
  909. screentrace_callback(Widget w unused, XtPointer client_data,
  910.     XtPointer call_data unused)
  911. {
  912.     if (screentrace_cb(XawDialogGetValueString((Widget)client_data)))
  913.         XtPopdown(screentrace_shell);
  914. }
  915.  
  916. /* Callback for second "OK" button on screentrace popup */
  917. static void
  918. onescreen_callback(Widget w, XtPointer client_data, XtPointer call_data unused)
  919. {
  920.     char *tfn;
  921.  
  922.     if (w)
  923.         tfn = XawDialogGetValueString((Widget)client_data);
  924.     else
  925.         tfn = (char *)client_data;
  926.     tfn = do_subst(tfn, True, True);
  927.     screentracef = fopen(tfn, "a");
  928.     if (screentracef == (FILE *)NULL) {
  929.         popup_an_errno(errno, tfn);
  930.         XtFree(tfn);
  931.         return;
  932.     }
  933.     (void) fcntl(fileno(screentracef), F_SETFD, 1);
  934.     XtFree(tfn);
  935.  
  936.     /* Save the current image, once. */
  937.     do_screentrace();
  938.  
  939.     /* Close the file, we're done. */
  940.     (void) fclose(screentracef);
  941.     screentracef = (FILE *)NULL;
  942.  
  943.     if (w)
  944.         XtPopdown(screentrace_shell);
  945. }
  946. #endif /*]*/
  947.  
  948. void
  949. toggle_screenTrace(struct toggle *t unused, enum toggle_type tt)
  950. {
  951.     char tracefile_buf[256];
  952.     char *tracefile;
  953.  
  954.     if (toggled(SCREEN_TRACE)) {
  955.         if (appres.screentrace_file)
  956.             tracefile = appres.screentrace_file;
  957.         else {
  958.             (void) sprintf(tracefile_buf, "%s/x3scr.%d",
  959.                 appres.trace_dir, getpid());
  960.             tracefile = tracefile_buf;
  961.         }
  962.         if (tt == TT_INITIAL) {
  963.             (void) screentrace_cb(NewString(tracefile));
  964.             return;
  965.         }
  966. #if defined(X3270_DISPLAY) /*[*/
  967.         if (screentrace_shell == NULL) {
  968.             screentrace_shell = create_form_popup("screentrace",
  969.                 screentrace_callback, onescreen_callback,
  970.                 FORM_NO_WHITE);
  971.             XtVaSetValues(XtNameToWidget(screentrace_shell,
  972.                     ObjDialog),
  973.                 XtNvalue, tracefile,
  974.                 NULL);
  975.         }
  976.         appres.toggle[SCREEN_TRACE].value = False;
  977.         appres.toggle[SCREEN_TRACE].changed = True;
  978.         popup_popup(screentrace_shell, XtGrabExclusive);
  979. #endif /*]*/
  980.     } else {
  981.         if (ctlr_any_data() && !trace_skipping)
  982.             do_screentrace();
  983.         (void) fclose(screentracef);
  984.     }
  985. }
  986.  
  987. #endif /*]*/
  988.